<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>画廊-小米关系图谱</title>
</head>

<body>
  <div style="position:relative; background: #e5ddd1;">
    <div id="mountNode"></div>
    <div id="minimap" style="position:absolute; bottom: 0px; right: 0px;"></div>
  </div>
  <p>数据来源：企查查</p>
  <p>描述：展示了 小米科技有限责任公司 的企业关系图谱</p>
  <script src="./assets/jquery-3.2.1.min.js"></script>
  <script src="./assets/d3-4.13.0.min.js"></script>
  <script src="./assets/d3-legend-2.25.6.min.js"></script>
  <script src="../build/g6.js"></script>
  <script src="../build/behaviourAnalysis.js"></script>
  <script src="../build/toolD3Mapper.js"></script>
  <script>
    $.getJSON('./assets/data/xiaomi.json', data => {
      const Mapper = window.ToolD3Mapper;
      const { forceSimulation, forceLink, forceManyBody, forceX, forceY, forceCollide } = d3;
      const nodeMap = {};
      const nodeSizeMapper = new Mapper('node', 'degree', 'size', [8, 48], {
        legendCfg: null
      });
      const nodeColorMapper = new Mapper('node', 'type', 'color', ['#e18826', '#002a67']);
      const G = G6.G;
      let simulation;
      const graph = new G6.Graph({
        container: 'mountNode',
        height: window.innerHeight,
        plugins: [nodeSizeMapper, nodeColorMapper],
        modes: {
          default: ['rightPanCanvas']
        },
        layout(nodes, edges) {
          if (simulation) {
            simulation.alphaTarget(0.3).restart();
          } else {
            simulation = forceSimulation(nodes)
              .force('charge', forceManyBody().strength(-100))
              .force('link', forceLink(edges).id(model => {
                return model.id;
              }))
              .force('collision', forceCollide().radius(model => {
                return model.size / 2 * 1.2;
              }))
              .force('y', forceY())
              .force('x', forceX())
              .on('tick', () => {
                graph.updateNodePosition();
              });
          }
        }
      });
      graph.node({
        style(model) {
          if (model.type === 'Company') {
            return {
              fill: '#e18826',
              shadowColor: 'rgba(0,0,0, 0.3)',
              shadowBlur: 3,
              shadowOffsetX: 2,
              shadowOffsetY: 2,
              stroke: null
            }
          }
          return {
            fill: '#002a67',
            shadowColor: 'rgba(0,0,0, 0.3)',
            shadowBlur: 3,
            shadowOffsetX: 3,
            shadowOffsetY: 5,
            stroke: null
          }
        },
        label(model) {
          return {
            text: model.properties['name'],
            stroke: null,
            fill: '#fff'
          };
        }
      });
      graph.edge({
        style() {
          return {
            stroke: '#b3b3b3',
            lineWidth: 2
          }
        }
      });
      graph.read(data);
      graph.translate(graph.getWidth() / 2, graph.getHeight() / 2);

      // 拖拽节点交互
      let subject; // 逼近点
      graph.on('mousedown', ev => {
        if (ev.domEvent.button === 0) {
          subject = simulation.find(ev.x, ev.y);
        }
      });

      graph.on('dragstart', ev => {
        subject && simulation.alphaTarget(0.3).restart();
      });

      graph.on('drag', ev => {
        if (subject) {
          subject.fx = ev.x;
          subject.fy = ev.y;
        }
      });

      graph.on('mouseup', resetState);
      graph.on('canvas:mouseleave', resetState);

      function resetState() {
        if (subject) {
          simulation.alphaTarget(0);
          subject.fx = null;
          subject.fy = null;
          subject = null
        }
      }

      // 鼠标移入节点显示 label
      function tryHideLabel(node) {
        const model = node.getModel();
        const label = node.getLabel();
        const labelBox = label.getBBox();
        if (labelBox.maxX - labelBox.minX > model.size) {
          label.hide();
          graph.draw();
        }
      }
      const nodes = graph.getNodes();
      const edges = graph.getEdges();

      edges.forEach(edge => {
        edge.getGraphicGroup().set('capture', false); // 移除边的捕获，提升图形拾取效率
      });

      nodes.forEach(node => {
        tryHideLabel(node);
      });

      graph.on('node:mouseenter', ev => {
        const item = ev.item;
        graph.toFront(item);
        item.getLabel().show();
        graph.draw();
      });

      graph.on('node:mouseleave', ev => {
        const item = ev.item;
        tryHideLabel(item);
      });
    });

  </script>
</body>

</html>
